package org.nvframe.component.physics.util;

import org.jbox2d.collision.shapes.CircleShape;
import org.jbox2d.collision.shapes.PolygonShape;
import org.jbox2d.collision.shapes.Shape;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.Body;
import org.jbox2d.dynamics.World;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.geom.Circle;
import org.newdawn.slick.geom.Polygon;
import org.newdawn.slick.geom.Transform;
import org.nvframe.camera.Camera;
import org.nvframe.event.EventService;
import org.nvframe.event.eventtype.RenderEvent;
import org.nvframe.event.eventtype.RenderListener;
import org.nvframe.manager.ConfigManager;
import org.nvframe.util.NVMathUtils;

/**
 * 
 * @author Nik Van Looy
 */
public class PhysicsDebugDraw implements RenderListener {
	
	private World world;
	
	public PhysicsDebugDraw(World world) {
		this.world = world;
		
		EventService.getInstance().addEventListener(this);
	}
	
	/**
	 * 
	 * @param g
	 */
	protected void drawBodies(Graphics g, GameContainer gc) {
		Body body = world.getBodyList();
		
		while(body != null) {
			drawBody(g, gc, body);
			body = body.getNext();
		} 
	}
	
	/**
	 * 
	 * @param g
	 * @param body
	 */
	protected void drawBody(Graphics g, GameContainer gc, Body body) {
		Shape shape = body.getShapeList();
		
		while(shape != null) {
			drawShape(g, gc, shape, body);
			shape = shape.getNext();
		} 
	}

	/**
	 * 
	 * @param g
	 * @param shape
	 * @param body
	 */
	private void drawShape(Graphics g, GameContainer gc, Shape shape, Body body) {
		Camera camera = Camera.getInstance();
		
		camera.translateGraphics(gc);
		
		switch(shape.getType()) {
			case CIRCLE_SHAPE:
				CircleShape circle = (CircleShape) shape;
            
	            Circle slickCircle = new Circle(circle.getLocalPosition().x, circle.getLocalPosition().y,
	            		circle.getRadius() * NVMathUtils.PIXELS_PER_METER);
	            
	            slickCircle.setLocation(body.getPosition().x * NVMathUtils.PIXELS_PER_METER, 
	            		body.getPosition().y * NVMathUtils.PIXELS_PER_METER);
	            slickCircle.setCenterX(body.getWorldCenter().x * NVMathUtils.PIXELS_PER_METER);
	            slickCircle.setCenterY(body.getWorldCenter().y * NVMathUtils.PIXELS_PER_METER);
				
	            g.draw(slickCircle);
	            
				break;
				
			case POLYGON_SHAPE:
				PolygonShape poly = (PolygonShape) shape;

				Polygon slickPoly = new Polygon();
				Transform transform = Transform.createRotateTransform(body.getAngle(), 
						body.getWorldCenter().x * NVMathUtils.PIXELS_PER_METER, 
						body.getWorldCenter().y * NVMathUtils.PIXELS_PER_METER);
				
				for(Vec2 vert : poly.getVertices())
					slickPoly.addPoint(vert.x * NVMathUtils.PIXELS_PER_METER, vert.y * NVMathUtils.PIXELS_PER_METER);
				
				slickPoly.setLocation(body.getPosition().x * NVMathUtils.PIXELS_PER_METER, 
						body.getPosition().y * NVMathUtils.PIXELS_PER_METER);
				slickPoly.setCenterX(body.getWorldCenter().x * NVMathUtils.PIXELS_PER_METER);
				slickPoly.setCenterY(body.getWorldCenter().y * NVMathUtils.PIXELS_PER_METER);
				slickPoly.transform(transform);
				
				g.draw(slickPoly);
				
				break;
				
			default:
				break;
		}
		
		if(ConfigManager.getInstance().getActive("engine_physics_showposition"))
			g.drawString("pos x: " + body.getPosition().x + " | pos y: " + body.getPosition().y, 
					body.getPosition().x * NVMathUtils.PIXELS_PER_METER + 20, 
					body.getPosition().y * NVMathUtils.PIXELS_PER_METER + 20);
		
		camera.untranslateGraphics(gc);
	}

	@Override
	public void onRender(RenderEvent event) {
		if(ConfigManager.getInstance().getActive("engine_physics_drawbodies"))
			drawBodies(event.getGr(), event.getGc());
	}
}
